package org.listbeast.core.youtubeclient;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import com.google.gdata.client.Query;
import com.google.gdata.client.youtube.YouTubeQuery;
import com.google.gdata.client.youtube.YouTubeQuery.OrderBy;
import com.google.gdata.client.youtube.YouTubeService;
import com.google.gdata.data.Category;
import com.google.gdata.data.youtube.VideoEntry;
import com.google.gdata.data.youtube.VideoFeed;
import com.google.gdata.data.youtube.YouTubeNamespace;
import com.google.gdata.util.ServiceException;

/**
 * @author ody
 */
public class YoutubeClient {

	private static final Logger LOG = Logger.getLogger(YoutubeClient.class);

	// The URL of the "Most Viewed" feed
	private final String MOST_VIEWED_FEED = "http://gdata.youtube.com/feeds/api/standardfeeds/most_viewed";
	// The URL of the "Videos" feed
	private final String VIDEOS_FEED = "http://gdata.youtube.com/feeds/api/videos";
	private static final int TIMEOUT = 5000; // connection timeout in millis
	private static final YouTubeService APPLICATION_SERVICE = new YouTubeService(
			YoutubeClient.class.getName());

	static {
		APPLICATION_SERVICE.setConnectTimeout(TIMEOUT);
	}

	/**
	 * 
	 * @param artistName
	 * @param offset
	 *            The youtube query will return a list of video titles ordered
	 *            by view count. Offset is used to specify the index of the
	 *            first element we want in the returned list
	 * @param maxResults
	 *            maximum number of returned results
	 * @return List of video entries for given artist
	 * @throws IOException
	 * @throws ServiceException
	 */
	public List<VideoEntry> findVideosOrderedByViewCount(String artistName,
			int offset, int maxResults) throws IOException, ServiceException {
		return findVideos(artistName, YouTubeQuery.OrderBy.VIEW_COUNT, offset,
				maxResults);
	}

	/**
	 * 
	 * @param artistName
	 * @param offset
	 *            The youtube query will return a list of video titles ordered
	 *            by relevance to the artist name. Offset is used to specify the
	 *            index of the first element we want in the returned list
	 * @param maxResults
	 *            maximum number of returned results
	 * @return A list of the most relevant youtube video entries for keyword the
	 *         artist name.
	 * @throws IOException
	 * @throws ServiceException
	 */
	public List<VideoEntry> findVideosOrderedByRelevance(String artistName,
			int offset, int maxResults) throws IOException, ServiceException {
		return findVideos(artistName, YouTubeQuery.OrderBy.RELEVANCE, offset,
				maxResults);
	}

	private List<VideoEntry> findVideos(String artistName, OrderBy orderBy, int offset, int maxResults) throws IOException, ServiceException {
		
		YouTubeQuery query = new YouTubeQuery(new URL(VIDEOS_FEED));

		query.setSafeSearch(YouTubeQuery.SafeSearch.NONE);
		query.setMaxResults(maxResults);
		query.setStartIndex(offset);
		query.setFullTextQuery(artistName);
		query.setOrderBy(orderBy);
		
		Query.CategoryFilter categoryFilter = new Query.CategoryFilter();
		categoryFilter.addCategory(new Category(YouTubeNamespace.CATEGORY_SCHEME, "Music"));
		query.addCategoryFilter(categoryFilter);

		VideoFeed videoFeed = APPLICATION_SERVICE.query(query, VideoFeed.class);

		return videoFeed.getEntries();

	}

	public String checkDidYouMean(String artistName) {

		URL google;
		String didyoumean = "";

		try {
			String artistNameTemp = artistName.replaceAll("[^\\d\\s\\w]", " ");
			artistNameTemp = artistNameTemp.replaceAll("[ ]+", "+");
			google = new URL("http://www.youtube.com/results?search_query="
					+ artistNameTemp + "&aq=f");

			Writer out = new StringWriter();
			IOUtils.copy(google.openStream(), out);

			String htmlData = "";
			htmlData = out.toString();
			// cannot do with replaceAll / replaceFirst because they are very
			// slow!
			// Should use XML parser instead
			htmlData = htmlData
					.replaceFirst(
							"(.*)(<span class=\"didyoumean\">.*</i></b></a>      </span>)(.*)",
							"$2");
			didyoumean = htmlData.replaceFirst("(.*<b><i>)(.*)(</i></b>.*)",
					"$2");

			LOG.info("-------->New artist name (from didyoumean): "
					+ didyoumean);

		} catch (IOException e) {
			LOG.error(e);
		}
		return didyoumean;
	}

}
